package com.ecole.mines.utils;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.text.format.DateFormat;
import android.util.Log;

import com.ecole.mines.model.Cours;
import com.ecole.mines.model.Eleve;
import com.ecole.mines.model.Promotion;
import com.ecole.mines.model.Signature;

public class WriteJSON extends AsyncTask<String, Integer, Boolean> {

	private Promotion promotion;
	private File fileDir;
	private String nomFichier;
	public static final String EXTERNAL_DIR = "Emargement";
	private static final String TAG = "WriteJSON";
	private String repertory;
	private ArrayList<Eleve> listeEleves;
	private JSONArray firstArray = new JSONArray();
	private JSONObject objetJson = new JSONObject();
	private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");

	public WriteJSON(Promotion p) {
		this.promotion = p;
		Cours c = this.promotion.getCours().get(0);
		this.repertory = this.promotion.getName().replace(" ", "")
				+ File.separator + c.getGroupe() + "_" + c.getId()
				+ File.separator;
		
		this.nomFichier = this.promotion.getId() + "_"
				+ this.promotion.getCours().get(0).getId() + "_"
				+ this.promotion.getCours().get(0).getGroupe() + ".json";
		
		File f = new File(Environment.getExternalStorageDirectory().getPath()
				+ File.separator + EXTERNAL_DIR + File.separator
				+ this.repertory + this.nomFichier);
		
		if (!f.exists()) {
			this.creerFichierJson();
		} else {
			try {
				FileInputStream in = new FileInputStream(f);
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(in, "utf-8"));
				StringBuilder sb = new StringBuilder();
				String line = null;
				while ((line = reader.readLine()) != null) {
					sb.append(line + "\n");
				}
				in.close();
				firstArray = new JSONArray(sb.toString());
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	@Override
	protected Boolean doInBackground(String... params) {
		return envoyerJson();
	}

	public void creerFichierJson() {
		Cours c = this.promotion.getCours().get(0);
		try {
			objetJson.put("id_groupe", c.getGroupe());
			objetJson.put("idcybemacours", c.getId());
			objetJson.put("name_promo", this.promotion.getName());
			objetJson.put("datefincours",
					DateFormat.format("yyyy-MM-dd ", c.getDate()).toString()
							+ DateFormat.format("kk:mm:ss", c.getHeureFin())
									.toString());
			objetJson.put("datedebutcours",
					DateFormat.format("yyyy-MM-dd ", c.getDate()).toString()
							+ DateFormat.format("kk:mm:ss", c.getHeureDebut())
									.toString());
			objetJson.put("libellecours", c.getNom());
			objetJson.put("sallecours", c.getSalle());
			objetJson.put("profcours", c.getProf());
			objetJson.put("id_promo", this.promotion.getId());

		} catch (JSONException e1) {
			e1.printStackTrace();
		}

		firstArray.put(objetJson);
		createDirectoryAndSaveFile(firstArray.toString(),
				this.promotion.getId() + "_"
						+ this.promotion.getCours().get(0).getId() + "_"
						+ this.promotion.getCours().get(0).getGroupe()
						+ ".json");
	}

	/**
	 * Recherche si l'eleve est présent dans le JSON
	 * 
	 * @param eleve
	 *            l'eleve a chercher
	 * @return vrai si l'eleve existe, faux sinon
	 */
	public boolean rechercherEleve(Eleve eleve) {
		try {
			JSONArray tableauEleve = this.firstArray.getJSONObject(0)
					.optJSONArray("eleves");
			if (tableauEleve == null || tableauEleve.length() == 0) {
				return false;
			} else {
				for (int i = 0; i < tableauEleve.length(); i++) {
					JSONObject eleveTemp = (JSONObject) tableauEleve.get(i);
					if (eleveTemp.optInt("ideleve") == eleve.getId()) {
						return true;
					}
				}
				return false;
			}
		} catch (JSONException e) {
			Log.w(TAG, e);
			return false;
		}
	}

	/**
	 * Ajoute l'eleve et sa signature dans le json
	 * 
	 * @param eleve
	 *            l'eleve a ajouter
	 * @return retourne vrai si l'élève a pu être ajouté, faux si une exception
	 *         a été levée
	 */
	public boolean enregistrerEleve(Eleve eleve) {
		JSONObject eleveTemp = new JSONObject();
		JSONArray tabEleve = new JSONArray();

		try {
			tabEleve = this.firstArray.getJSONObject(0).optJSONArray("eleves");
			if (tabEleve == null) {
				tabEleve = new JSONArray();
				this.firstArray.getJSONObject(0).put("eleves", tabEleve);
			}
			if (eleve.getHasSigned() && eleve.getSignatures() != null
					&& eleve.getSignatures().size() > 0) {
				Signature s = eleve.getSignatures().get(0);
				eleveTemp.put("signature", s.getDirectory() + File.separator
						+ s.getNamefile());
				eleveTemp.put(
						"horodatage",
						DateFormat.format("yyyy-MM-dd kk:mm:ss",
								s.getHeureSignature()));
			} else {
				eleveTemp.put("horodatage", "false");
			}
			eleveTemp.put("name", eleve.getNom() + " " + eleve.getPrenom());
			eleveTemp.put("ideleve", eleve.getId());
			tabEleve.put(eleveTemp);

			this.ecrireJson();
		} catch (JSONException e) {
			Log.w(TAG, e);
			return false;
		}
		return true;
	}

	/**
	 * Met à jour les informations de l'eleve
	 * 
	 * @param eleve
	 *            l'eleve a mettre à jour
	 * @return retourne vrai si l'élève a pu être modifié, faux si une exception
	 *         a été levée
	 */
	public boolean modifierEleve(Eleve eleve) {
		JSONObject eleveTemp = new JSONObject();
		JSONArray tabEleve = new JSONArray();

		try {
			tabEleve = this.firstArray.getJSONObject(0).optJSONArray("eleves");
			eleveTemp = this.rechercherEleveJson(eleve);
			if (eleveTemp == null) {
				eleveTemp = new JSONObject();
				tabEleve.put(eleveTemp);
			}

			if (eleve.getSignatures() != null
					&& eleve.getSignatures().size() > 0) {
				Signature s = eleve.getSignatures().get(0);
				eleveTemp.put("signature", s.getDirectory() + s.getNamefile());
				eleveTemp.put(
						"horodatage",
						DateFormat.format("yyyy-MM-dd kk:mm:ss",
								s.getHeureSignature()));

			}
			eleveTemp.put("name", eleve.getNom() + " " + eleve.getPrenom());
			eleveTemp.put("ideleve", eleve.getId());

			this.ecrireJson();
		} catch (JSONException e) {
			Log.w(TAG, e);
			return false;
		}
		return true;
	}

	/**
	 * Recherche l'objet JSON de l'eleve
	 * 
	 * @param tabEleve
	 *            le JSONArray des eleves
	 * @param eleve
	 *            l'eleve a rechercher
	 * @return l'objet JSON de l'eleve, null s'il n'existe pas
	 */
	private JSONObject rechercherEleveJson(Eleve eleve) {
		JSONArray tabEleve = new JSONArray();
		try {
			tabEleve = this.firstArray.getJSONObject(0).optJSONArray("eleves");
			for (int i = 0; i < tabEleve.length(); i++) {
				if (tabEleve.getJSONObject(i).optInt("ideleve") == eleve
						.getId()) {
					return tabEleve.getJSONObject(i);
				}
			}
		} catch (JSONException e1) {
			e1.printStackTrace();
		}
		return null;
	}

	public void printJson() {
		System.out.println(this.firstArray);
	}

	/**
	 * Permet d'écrire les modifications de l'objet JSON dans le fichier json
	 * présent sur le stockage externe
	 */
	public void ecrireJson() {
		BufferedWriter writer = null;
		fileDir = new File(new File(Environment.getExternalStorageDirectory()
				+ File.separator + EXTERNAL_DIR + "/" + this.repertory),
				this.nomFichier);
		try {
			FileOutputStream out = new FileOutputStream(fileDir, false);
			writer = new BufferedWriter(new OutputStreamWriter(out, "utf-8"));
			writer.write(firstArray.toString());
			writer.flush();
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void createDirectoryAndSaveFile(String jsonToSave, String fileName) {
		BufferedWriter writer = null;
		File directory = new File(Environment.getExternalStorageDirectory()
				+ File.separator + EXTERNAL_DIR + "/" + this.repertory);
		directory.mkdirs();
		fileDir = new File(directory, fileName);

		if (fileDir.exists()) {
			fileDir.delete();
		}
		try {
			FileOutputStream out = new FileOutputStream(fileDir);
			writer = new BufferedWriter(new OutputStreamWriter(out, "utf-8"));

			writer.write(jsonToSave);
			writer.flush();
			out.flush();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void chargerEleves(ArrayList<Eleve> eleves) {
		for (Eleve eleve : eleves) {
			if (this.rechercherEleve(eleve)) {
				eleve.setHasSigned(true);
				ArrayList<Signature> signatures = new ArrayList<Signature>();
				JSONObject eleveJson = null;
				if ((eleveJson = this.rechercherEleveJson(eleve)) != null) {
					Signature s = new Signature();
					File f = new File(eleveJson.optString("signature"));
					s.setNamefile(f.getName());
					s.setDirectory(f.getParentFile());
					if (f.exists()) {
						BitmapFactory.Options options = new BitmapFactory.Options();
						options.inMutable=true;
						s.setImageSignature(BitmapFactory.decodeFile(f
								.getAbsolutePath(),options));
					}
					Date d;
					try {
						d = sdf.parse(eleveJson.optString("horodatage"));
						s.setHeureSignature(d.getTime());
					} catch (ParseException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					signatures.add(s);
					try {
						eleve.setSignatures(signatures);
					} catch (Exception e) {
						System.out.println("Excpetion " + e.getMessage());
					}
				}
			} else {
				eleve.setHasSigned(false);
			}
		}
	}

	/**
	 * Parcours la liste des élèves pour trouver les absents et les ajouter au
	 * JSON
	 */
	public void traitementEleveAbsent() {
		for (int i = 0; i < this.listeEleves.size(); i++) {
			Eleve e = this.listeEleves.get(i);
			if (!e.getHasSigned()) {
				this.enregistrerEleve(e);
			}
		}
	}

	public boolean envoyerJson() {
		// Avant d'envoyer le json, on le compléte pour les élèves absents
		this.traitementEleveAbsent();

		this.printJson();

		// Making HTTP request
		try {
			// defaultHttpClient
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpPost httpPost = new HttpPost(UtilsString.URL_SERVEUR
					+ UtilsString.ACTION_ENVOIE_JSON);
			httpPost.setHeader("Accept", "application/json");
			httpPost.setHeader("Content-type", "application/json");

			ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
			nameValuePairs.add(new BasicNameValuePair("json_signature",
					this.firstArray.toString()));
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
			HttpResponse httpResponse = httpClient.execute(httpPost);

			// HttpEntity httpEntity = httpResponse.getEntity();
			System.out
					.println("Status reponse " + httpResponse.getStatusLine());

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}

	public ArrayList<Eleve> getListeEleves() {
		return listeEleves;
	}

	public void setListeEleves(ArrayList<Eleve> listeEleves) {
		this.listeEleves = listeEleves;
	}
}
